package com.surfilter.msmp.web.system.service;

import com.surfilter.msmp.common.util.GsonUtil;
import com.surfilter.msmp.web.common.enums.EsCensusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 描述 ：统计业务类
 * 作者 ：WYH
 * 时间 ：2019/12/31 14:20
 **/
@Service
@Slf4j
public class CensusService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    //缓存map
    private Map<String, Map<String, String>> sourceCensusMap;

    private Map<String, Map<String, String>> blockCensusMap;
    //缓存过期时间
    private long expireTime = 0L;

    /**
     * 进行统计操作 缓存函数
     *
     * @param esCensusEnum 要统计的索引
     * @param type         统计周期
     */
    public Map<String, String> census(EsCensusEnum esCensusEnum, String type) {
        if (System.currentTimeMillis() > expireTime) {
            //清空缓存 缓存时长10分钟
            expireTime = System.currentTimeMillis() + 60 * 10 * 1000;
            sourceCensusMap = new HashMap<>(4);
            blockCensusMap = new HashMap<>(4);
        }
        if (esCensusEnum == null) {
            return null;
        }
        //根据不同索引放入不同缓存map
        switch (esCensusEnum) {
            case BLOCK_LOG: {
                if (blockCensusMap.get(type) == null) {
                    blockCensusMap.put(type, censusByType(type, esCensusEnum));
                }
                return blockCensusMap.get(type);
            }
            case UPDATE_LOG: {
                if (sourceCensusMap.get(type) == null) {
                    sourceCensusMap.put(type, censusByType(type, esCensusEnum));
                }
                return sourceCensusMap.get(type);
            }
            default: {
                break;
            }
        }
        return null;
    }

    /**
     * 根据不同枚举 搜索不同索引集 返回结果装配到map中
     */
    private Map<String, String> censusByType(String type, EsCensusEnum esCensusEnum) {
        Map<String, String> map = new HashMap<>(4);
        String[] indices;
        final String startTime = " 00:00:00";
        final String endTime = " 23:59:59";
        try {
            switch (esCensusEnum) {
                case UPDATE_LOG: {
                    //获取所有入口地址更新日志的索引 索引以年分割 可能不止一个索引
                    GetAliasesResponse getAliasesResponse = restHighLevelClient.indices().getAlias(new GetAliasesRequest(), RequestOptions.DEFAULT);
                    Set<String> tmpSet = getAliasesResponse.getAliases().keySet();
                    indices = tmpSet.stream().filter(s -> s.startsWith(esCensusEnum.getIndex())).distinct().toArray(String[]::new);
                    break;
                }
                case BLOCK_LOG: {
                    indices = new String[]{esCensusEnum.getIndex()};
                    break;
                }
                default: {
                    indices = new String[0];
                    break;
                }
            }
            switch (type) {
                case "day": {
                    //按日查询 则查询过去30天的
                    String[] resDate = new String[30];
                    Long[] resCount = new Long[30];
                    LocalDate start = LocalDate.now().minusDays(29);
                    for (int i = 0; i < 30; i++) {
                        String s = start.toString();
                        String from = s + startTime;
                        String to = s + endTime;
                        resDate[i] = s;
                        resCount[i] = getCount(from, to, esCensusEnum.getRangeField(), indices);
                        start = start.plusDays(1);
                    }
                    map.put("censusDate", GsonUtil.getJsonStringByObject(resDate));
                    map.put("censusCount", GsonUtil.getJsonStringByObject(resCount));
                    break;
                }
                case "month": {
                    //查询过去6个月的
                    String[] resDate = new String[6];
                    Long[] resCount = new Long[6];
                    LocalDate start = LocalDate.now().minusMonths(5);
                    for (int i = 0; i < 6; i++) {
                        String from = start.with(TemporalAdjusters.firstDayOfMonth()) + startTime;
                        String to = start.with(TemporalAdjusters.lastDayOfMonth()) + endTime;
                        resDate[i] = start.getYear() + "-" + start.getMonthValue();
                        resCount[i] = getCount(from, to, esCensusEnum.getRangeField(), indices);
                        start = start.plusMonths(1);
                    }
                    map.put("censusDate", GsonUtil.getJsonStringByObject(resDate));
                    map.put("censusCount", GsonUtil.getJsonStringByObject(resCount));
                    break;
                }
                case "year": {
                    //查询过去5年的
                    String[] resDate = new String[5];
                    Long[] resCount = new Long[5];
                    LocalDate start = LocalDate.now().minusYears(4);
                    for (int i = 0; i < 5; i++) {
                        String from = start.with(TemporalAdjusters.firstDayOfYear()) + startTime;
                        String to = start.with(TemporalAdjusters.lastDayOfYear()) + endTime;
                        resDate[i] = start.getYear() + "";
                        resCount[i] = getCount(from, to, esCensusEnum.getRangeField(), indices);
                        start = start.plusYears(1);
                    }
                    map.put("censusDate", GsonUtil.getJsonStringByObject(resDate));
                    map.put("censusCount", GsonUtil.getJsonStringByObject(resCount));
                    break;
                }
                default: {
                    break;
                }
            }
        } catch (IOException e) {
            log.error("统计入口地址更新数量出错：" + e);
        }

        return map;
    }

    /**
     * 按日期查询封堵日志数量
     *
     * @param rangeField 日期字段
     * @param indices    索引
     * @author wyh
     */
    public long getCount(String from, String to, String rangeField, String... indices) {
        if (indices.length == 0) {
            return 0;
        }
        long count = 0;
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        CountRequest request = new CountRequest(indices);
        if (StringUtils.isNotBlank(from) && StringUtils.isNotBlank(to)) {
            //条件查询
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.rangeQuery(rangeField).from(from).to(to));
            searchSourceBuilder.query(boolQueryBuilder);
        }
        request.source(searchSourceBuilder);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            count = response.getCount();
        } catch (IOException e) {
            log.error("统计查询出错：" + e);
        }
        return count;
    }
}
